package el.util.force;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import prefuse.util.force.AbstractForce;
import prefuse.util.force.ForceItem;
import prefuse.util.force.ForceSimulator;


public class WholeNBodyForceBruteForce extends WholeNBodyForce {

    /**
     * Create a new NBodyForce with default parameters.
     */
    public WholeNBodyForceBruteForce() {
      //  this(DEFAULT_GRAV_CONSTANT, DEFAULT_DISTANCE, DEFAULT_THETA);
    	this(-1.0f, -1f, 0.9f);
    }
    
    /**
     * Create a new NBodyForce.
     * @param gravConstant the gravitational constant to use. Nodes will
     * attract each other if this value is positive, and will repel each
     * other if it is negative.
     * @param minDistance the distance within which two particles will
     * interact. If -1, the value is treated as infinite.
     * @param theta the Barnes-Hut parameter theta, which controls when
     * an aggregated mass is used rather than drilling down to individual
     * item mass values.
     */
    public WholeNBodyForceBruteForce(float gravConstant, float minDistance, float theta) {
        params = new float[] { gravConstant, minDistance, theta };
        minValues = new float[] { DEFAULT_MIN_GRAV_CONSTANT,
            DEFAULT_MIN_DISTANCE, DEFAULT_MIN_THETA };
        maxValues = new float[] { DEFAULT_MAX_GRAV_CONSTANT,
            DEFAULT_MAX_DISTANCE, DEFAULT_MAX_THETA };
    }
    
    /**
     * Calculates the force vector acting on the given item.
     * @param item the ForceItem for which to compute the force
     */
    public void getForce(ForceItem item) {
    	for (ForceItem iitem :fi){
    		for (ForceItem jitem :fi)
	            forceHelper(iitem, jitem);
    	}
    }
    
    public void init(List<ForceItem> list){
    	init(list.iterator());
    }
    
    public void init(Iterator<ForceItem>  itemIter) {
    	fi = new ArrayList<ForceItem>();
        clear(); // clear internal state   
        while ( itemIter.hasNext() ) {
            ForceItem item = (ForceItem)itemIter.next();
            // EL
            fi.add(item);
            // EL
        }
    }
    
    public void clear() {


    }
    
    private void forceHelper(ForceItem item, ForceItem n)
    {
        float dx = n.location[0] - item.location[0];
        float dy = n.location[1] - item.location[1];
        float r  = (float)Math.sqrt(dx*dx+dy*dy);
        boolean same = false;
        //System.out.println(item.location[0]);
        if ((dx == 0)&&(dy == 0)) return;
        
        if ( r == 0.0f ) {
            // if items are in the exact same place, add some noise
            dx = (rand.nextFloat()-0.5f) / 50.0f;
            dy = (rand.nextFloat()-0.5f) / 50.0f;
            r  = (float)Math.sqrt(dx*dx+dy*dy);
            same = true;
        }
        float v = params[GRAVITATIONAL_CONST]*item.mass*n.mass 
                / (r*r*r);
        item.force[0] += v*dx;
        item.force[1] += v*dy;
        
    }

} // end of class NBodyForce
